﻿using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Net;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
using Volo.Abp.DependencyInjection;

namespace FlyingEye.HttpServices
{
    /// <summary>
    /// HTTP 客户端服务
    /// </summary>
    public class HttpClientService : ITransientDependency 
    {
        private readonly IHttpClientFactory _httpClientFactory;
        private readonly HttpClientServiceOptions _options;
        private readonly HttpTokenManager _tokenManager;
        private readonly ILogger<HttpClientService> _logger;
        private readonly SemaphoreSlim _clientLock = new(1, 1);

        public HttpClientService(
            IHttpClientFactory httpClientFactory,
            IOptions<HttpClientServiceOptions> options,
            HttpTokenManager tokenManager,
            ILogger<HttpClientService> logger)
        {
            _httpClientFactory = httpClientFactory;
            _options = options.Value;
            _tokenManager = tokenManager;
            _logger = logger;
        }

        public async Task<TResult> GetAsync<TResult>(string url, bool requiresAuth = true)
            => await SendAsync<TResult>(HttpMethod.Get, url, requiresAuth: requiresAuth);

        public async Task<TResult> PostAsync<TResult, TValue>(string url, TValue value, bool requiresAuth = true)
            => await SendAsync<TResult>(HttpMethod.Post, url, value, requiresAuth);

        public async Task<TResult> PutAsync<TResult, TValue>(string url, TValue value, bool requiresAuth = true)
            => await SendAsync<TResult>(HttpMethod.Put, url, value, requiresAuth);

        public async Task<TResult> DeleteAsync<TResult>(string url, bool requiresAuth = true)
            => await SendAsync<TResult>(HttpMethod.Delete, url, requiresAuth: requiresAuth);

        private async Task<TResult> SendAsync<TResult>(
            HttpMethod method,
            string url,
            object? content = null,
            bool requiresAuth = true)
        {
            using var client = _httpClientFactory.CreateClient("MonitorServiceHttpClient");
            var request = await BuildRequestMessage(method, url, content, requiresAuth);

            try
            {
                var response = await client.SendAsync(request);
                return await HandleResponse<TResult>(response);
            }
            catch (HttpRequestException ex)
            {
                _logger.LogError(ex, "HTTP 请求失败: {Method} {Url}", method, url);
                throw new HttpClientServiceException("服务通信失败", ex);
            }
        }

        private async Task<HttpRequestMessage> BuildRequestMessage(
            HttpMethod method,
            string url,
            object? content,
            bool requiresAuth)
        {
            var request = new HttpRequestMessage(method, url);

            if (requiresAuth)
            {
                var token = await _tokenManager.GetBearerTokenAsync();
                request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.AccessToken);
            }

            if (content != null)
            {
                request.Content = JsonContent.Create(content, options: new JsonSerializerOptions
                {
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
                });
            }

            return request;
        }

        private static async Task<TResult> HandleResponse<TResult>(HttpResponseMessage response)
        {
            if (!response.IsSuccessStatusCode)
            {
                var errorContent = await response.Content.ReadAsStringAsync();
                throw new HttpClientServiceException($"HTTP 错误: {response.StatusCode}\n{errorContent}");
            }

            try
            {
                return await response.Content.ReadFromJsonAsync<TResult>()
                    ?? throw new InvalidDataException("响应内容为空");
            }
            catch (JsonException ex)
            {
                throw new HttpClientDataFormatException("JSON 反序列化失败", ex);
            }
        }
    }

    /// <summary>
    /// HTTP 客户端服务异常
    /// </summary>
    public class HttpClientServiceException : Exception
    {
        public HttpClientServiceException(string message, Exception? inner = null) : base(message, inner) { }
    }

    /// <summary>
    /// HTTP 客户端数据格式异常
    /// </summary>
    public class HttpClientDataFormatException : Exception
    {
        public HttpClientDataFormatException(string message, Exception inner) : base(message, inner) { }
    }
}